package com.yxinsur.imc.business.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

import com.yxinsur.imc.business.domain.ImcInsScheme;
import com.yxinsur.imc.business.domain.ImcRepoIns;
import com.yxinsur.imc.business.enums.IsDeletedEnum;
import com.yxinsur.imc.business.enums.RateTypeEnum;
import com.yxinsur.imc.business.excel.RateTemplate;
import com.yxinsur.imc.business.form.InsRateFactorForm;
import com.yxinsur.imc.business.form.InsRateForm;
import com.yxinsur.imc.business.form.OrderRiskForm;
import com.yxinsur.imc.business.mapper.ImcInsSchemeMapper;
import com.yxinsur.imc.business.mapper.ImcRepoInsMapper;
import com.yxinsur.imc.business.vo.InsRateVo;
import com.yxinsur.imc.business.vo.OrderRiskRateVo;
import com.yxinsur.imc.common.core.domain.entity.SysOrg;
import com.yxinsur.imc.common.exception.BusinessException;
import com.yxinsur.imc.common.utils.DateUtils;
import com.yxinsur.imc.common.utils.SecurityUtils;
import com.yxinsur.imc.common.utils.StringUtils;
import com.yxinsur.imc.common.utils.bean.MyBeanUtils;
import com.yxinsur.imc.common.validator.Assert;
import com.yxinsur.imc.system.mapper.SysOrgMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.yxinsur.imc.business.mapper.ImcInsRateMapper;
import com.yxinsur.imc.business.domain.ImcInsRate;
import com.yxinsur.imc.business.service.IImcInsRateService;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

/**
 * 险种产品费率表Service业务层处理
 *
 * @author imc
 * @date 2021-04-29
 */
@Service
public class ImcInsRateServiceImpl extends ServiceImpl<ImcInsRateMapper, ImcInsRate> implements IImcInsRateService {
    private static final Logger logger = LoggerFactory.getLogger(ImcInsRateServiceImpl.class);

    @Autowired
    private ImcInsRateMapper imcInsRateMapper;
    @Autowired
    private ImcRepoInsMapper imcRepoInsMapper;
    @Autowired
    private ImcInsSchemeMapper imcInsSchemeMapper;
    @Autowired
    private SysOrgMapper orgMapper;
    //区间默认最小LOWER
    private final static int lower_default = 1;
    //区间默认最大UPPER
    private final static int upper_default = 99999;

    /**
     * 查询险种产品费率表列表
     *
     * @param repoInsId 险种产品ID
     * @return 险种产品费率表
     */
    @Override
    public List<InsRateVo> selectImcInsRateList(Long repoInsId) {
        logger.info("查询指定产品的所有费率列表数据，产品ID：{}", repoInsId);
        String authOrgIds = SecurityUtils.getLoginUser().getAuthOrgIds();
        String[] orgIdArr = authOrgIds.split(",");
        List<Long> collect = Arrays.stream(orgIdArr).map(s -> Long.parseLong(s)).collect(Collectors.toList());
        Long[] orgIdLongs = new Long[collect.size()];
        collect.toArray(orgIdLongs);
        return imcInsRateMapper.selectImcInsRateList(repoInsId, SecurityUtils.getTenantId(), orgIdLongs);
    }

    /**
     * 导入险种费率数据
     *
     * @param rateType       费率类型，RCF
     * @param orgId          机构ID
     * @param repoSupplierId 供应商ID
     * @param rateList       费率数据
     * @return
     */
    @Override
    @Transactional
    public String importInsRate(String rateType, Long orgId, Long repoSupplierId, List<RateTemplate> rateList) {
        logger.info("险种费率导入，费率类型：{}，导入数据：{}条", rateList, rateList.size());
        if (StringUtils.isNull(rateList) || rateList.size() == 0) {
            throw new BusinessException("导入费率数据无有效数据！");
        }
        int successNum = 0;
        int failureNum = 0;
        StringBuilder successMsg = new StringBuilder();
        StringBuilder failureMsg = new StringBuilder();
        List<RateTemplate> validList = new ArrayList<>();

        Date date = DateUtils.getNowDate();//操作时间
        //校验数据
        for (RateTemplate template : rateList) {
            if (template.getIndex() != null) {
                StringBuffer errorMsg = new StringBuffer();
                Long repoInsId = null;//险种产品库ID
                if (StringUtils.isBlank(template.getInsCode())) {
                    errorMsg.append("险种代码不能为空；");
                } else {
                    QueryWrapper<ImcRepoIns> insQueryWrapper = new QueryWrapper<>();
                    insQueryWrapper.eq("repo_supplier_id", repoSupplierId);
                    insQueryWrapper.eq("ins_code", template.getInsCode());
                    insQueryWrapper.eq("is_deleted", IsDeletedEnum.N.getCode());
                    List<ImcRepoIns> insList = this.imcRepoInsMapper.selectList(insQueryWrapper);
                    if (insList.size() == 0) {
                        errorMsg.append("供应商下不存在此险种代码（" + template.getInsCode() + "）；");
                    } else if (insList.size() == 1) {
                        repoInsId = insList.get(0).getId();
                    } else {
                        errorMsg.append("产品库中险种内部代码异常：（" + template.getInsCode() + "）；");
                    }
                }
                if (template.getRate() == null) {
                    errorMsg.append("费率不能为空；");
                }
                //执行插入数据
                ImcInsRate rate = new ImcInsRate();
                BeanUtils.copyProperties(template, rate);
                //默认值处理
                this.defaultValue(rate);
                //方案处理
                if (StringUtils.isNotBlank(template.getInsSchemeValue())) {
                    QueryWrapper<ImcInsScheme> schemeQueryWrapper = new QueryWrapper<>();
                    schemeQueryWrapper.eq("repo_ins_id", repoInsId);
                    schemeQueryWrapper.eq("ins_scheme_value", template.getInsSchemeValue());
                    schemeQueryWrapper.eq("is_deleted", IsDeletedEnum.N.getCode());
                    schemeQueryWrapper.eq("tenant_id", SecurityUtils.getTenantId());
                    List<ImcInsScheme> schemeList = this.imcInsSchemeMapper.selectList(schemeQueryWrapper);
                    if (schemeList.size() == 0) {
                        errorMsg.append("方案（" + template.getInsSchemeValue() + "）不存在；");
                    } else if (schemeList.size() == 1) {
                        rate.setInsSchemeId(schemeList.get(0).getId());
                    } else {
                        errorMsg.append("方案（" + template.getInsSchemeValue() + "）在系统中配置有重复；");
                    }
                }
                rate.setRateType(rateType);
                rate.setOrgId(orgId);
                rate.setRepoInsId(repoInsId);
                rate.setCreateTime(date);
                rate.setCreateId(SecurityUtils.getUsername());
                rate.setIsDeleted(IsDeletedEnum.N.getCode());
                rate.setTenantId(SecurityUtils.getTenantId());
                try {
                    //校验是否存在
                    if (this.checkExsit(rate)) {
                        errorMsg.append("费率已存在（勿重复导入）；");
                    } else {
                        this.imcInsRateMapper.insert(rate);
                    }
                    successNum++;
                } catch (Exception e) {
                    errorMsg.append("本条数据与已配置数据有交集或数据校验不通过；");
                }

                if (errorMsg.length() > 0) {
                    errorMsg.insert(0, "序号" + template.getIndex() + ":");
                    errorMsg.append("\n<br/>");
                    failureNum++;
                } else {
                    validList.add(template);
                }
                failureMsg.append(errorMsg);
            }
        }
        if (failureNum > 0) {
            failureMsg.insert(0, "很抱歉，导入失败！共 " + failureNum + " 条数据格式不正确，错误如下：\n<br/>");
            throw new BusinessException(failureMsg.toString());
        }
        return successMsg.append("恭喜您，数据已导入成功！共 " + successNum + " 条").toString();
    }

    //校验费率是否重复
    private boolean checkExsit(ImcInsRate rate) {
        QueryWrapper<ImcInsRate> checkWrapper = new QueryWrapper<>();
        checkWrapper.eq("repo_ins_id", rate.getRepoInsId());
        checkWrapper.eq("org_id", rate.getOrgId());
        checkWrapper.eq("rate_type", rate.getRateType());
        checkWrapper.eq("charge_period_lower_value", rate.getChargePeriodLowerValue());
        checkWrapper.eq("charge_period_upper_value", rate.getChargePeriodUpperValue());
        checkWrapper.eq("coverage_period_lower_value", rate.getCoveragePeriodLowerValue());
        checkWrapper.eq("coverage_period_upper_value", rate.getCoveragePeriodUpperValue());
        checkWrapper.eq("pension_age_lower", rate.getPensionAgeLower());
        checkWrapper.eq("pension_age_upper", rate.getPensionAgeUpper());
        checkWrapper.eq("pay_year_lower", rate.getPayYearLower());
        checkWrapper.eq("pay_year_upper", rate.getPayYearUpper());
        checkWrapper.eq("ins_scheme_id", rate.getInsSchemeId());
        checkWrapper.eq("charge_interval_enum", rate.getChargeIntervalEnum());
        checkWrapper.eq("factor1_value", rate.getFactor1Value());
        checkWrapper.eq("factor2_value", rate.getFactor2Value());
        checkWrapper.eq("factor3_value", rate.getFactor3Value());
        checkWrapper.eq("start_time", rate.getStartTime());
        checkWrapper.eq("end_time", rate.getEndTime());
        checkWrapper.eq("is_deleted", IsDeletedEnum.N.getCode());
        checkWrapper.eq("tenant_id", rate.getTenantId());
        List<ImcInsRate> list = this.imcInsRateMapper.selectList(checkWrapper);
        return list.size() > 0 ? true : false;
    }

    /**
     * 新增险种产品费率表
     *
     * @param insRateForm 险种产品费率表
     * @return 结果
     */
    @Override
    public int insertImcInsRate(InsRateForm insRateForm) {
        logger.info("新增险种产品费率，数据：{}", insRateForm.toString());
        //校验费率
        QueryWrapper<ImcInsRate> checkWrapper = new QueryWrapper<>();
        checkWrapper.eq("repo_ins_id", insRateForm.getRepoInsId());
        checkWrapper.eq("org_id", insRateForm.getOrgId());
        checkWrapper.eq("rate_type", insRateForm.getRateType());
        checkWrapper.eq("charge_period_lower_value", insRateForm.getChargePeriodLowerValue());
        checkWrapper.eq("charge_period_lower_value", insRateForm.getChargePeriodLowerValue());
        checkWrapper.eq("charge_period_upper_value", insRateForm.getChargePeriodLowerValue());

        ImcInsRate rate = new ImcInsRate();
        BeanUtils.copyProperties(insRateForm, rate);
        //默认值处理
        this.defaultValue(rate);
        rate.setCreateTime(DateUtils.getNowDate());
        rate.setCreateId(SecurityUtils.getUsername());
        rate.setIsDeleted(IsDeletedEnum.N.getCode());
        rate.setTenantId(SecurityUtils.getTenantId());
        return this.imcInsRateMapper.insert(rate);
    }

    /**
     * 修改险种产品费率表
     *
     * @param insRateForm 险种产品费率表
     * @return 结果
     */
    @Override
    public int updateImcInsRate(InsRateForm insRateForm) {
        logger.info("修改险种产品费率，数据：{}", insRateForm.toString());
        Assert.isNull(insRateForm.getId(), "传参有误，ID不能为空");
        ImcInsRate rate = this.imcInsRateMapper.selectById(insRateForm.getId());
        BeanUtils.copyProperties(insRateForm, rate);
        //默认值处理
        this.defaultValue(rate);
        rate.setUpdateTime(DateUtils.getNowDate());
        rate.setUpdateId(SecurityUtils.getUsername());
        return this.imcInsRateMapper.updateById(rate);
    }

    //处理保障年期领取年龄默认值问题
    public void defaultValue(ImcInsRate rate) {
        if (rate.getCoveragePeriodLowerValue() == null || rate.getCoveragePeriodUpperValue() == null) {
            rate.setCoveragePeriodLowerValue(lower_default);
            rate.setCoveragePeriodUpperValue(upper_default);
        }
        if (rate.getPensionAgeLower() == null || rate.getPensionAgeUpper() == null) {
            rate.setPensionAgeLower(lower_default);
            rate.setPensionAgeUpper(upper_default);
        }
        if (StringUtils.isBlank(rate.getChargeIntervalEnum())) {
            rate.setChargeIntervalEnum("B,C,D,E");
        }
    }

    /**
     * 批量删除险种产品费率表
     *
     * @param ids 需要删除的险种产品费率表ID
     * @return 结果
     */
    @Override
    public int deleteImcInsRateByIds(Long[] ids) {
        logger.info("险种产品费率删除操作：{}", ids);
        int count = 0;
        for (Long id : ids) {
            ImcInsRate rate = this.imcInsRateMapper.selectById(id);
            rate.setIsDeleted(rate.getId().toString());
            rate.setUpdateId(SecurityUtils.getUsername());
            rate.setUpdateTime(DateUtils.getNowDate());
            count += this.imcInsRateMapper.updateById(rate);
        }
        return count;
    }

    /**
     * 获取险种产品费率表
     *
     * @param riskForm 险种产品信息
     * @return 结果
     */
    @Override
    public OrderRiskRateVo getRates(OrderRiskForm riskForm) {
        OrderRiskRateVo vo = new OrderRiskRateVo();
        //查询该险种各种费率
        //佣金率
        ImcInsRate cRate = this.getRateOne(riskForm, RateTypeEnum.C.getCode());
        if (cRate != null) {
            vo.setCommissionRate(cRate.getRate());
            vo.setHasCommissionRate(true);
        } else {
            vo.setHasCommissionRate(false);
        }
        //折标
        ImcInsRate RRate = this.getRateOne(riskForm, RateTypeEnum.R.getCode());
        if (RRate != null) {
            vo.setStandRate(RRate.getRate());
            vo.setHasStandRate(true);
        } else {
            vo.setHasStandRate(false);
        }
        //年期
        ImcInsRate YSRate = this.getRateOne(riskForm, RateTypeEnum.YS.getCode());
        if (YSRate != null) {
            vo.setYearScale(YSRate.getRate());
            vo.setHasFeeRate(true);
        } else {
            vo.setHasFeeRate(false);
        }
        //供应商
        ImcInsRate SRRate = this.getRateOne(riskForm, RateTypeEnum.SR.getCode());
        if (SRRate != null) {
            vo.setSupplierStandRate(SRRate.getRate());
            vo.setHasSupplierStandRate(true);
        } else {
            vo.setHasSupplierStandRate(false);
        }
        return vo;
    }

    /**
     * 查询佣金费率
     *
     * @param riskForm
     * @param code
     * @return
     */
    private ImcInsRate getRateOne(OrderRiskForm riskForm, String code) {
//        Long inputOrgId = riskForm.getInputOrgId();
        //使用结算机构字段获取费率
        Long settleOrgId = riskForm.getSettleOrgId();
        SysOrg sysOrg = orgMapper.selectOrgById(settleOrgId);
        String ancestors = sysOrg.getAncestors();
        ArrayList orgIds = new ArrayList<String>(Arrays.asList(ancestors.split(",")));
        orgIds.add(String.valueOf(settleOrgId));
        ImcInsRate returnRate = null;
        for (int i = orgIds.size() - 1; i > 0; i--) {
            QueryWrapper<ImcInsRate> rateQueryWrapper = new QueryWrapper<>();
            rateQueryWrapper.eq("repo_ins_id", riskForm.getRepoInsId());
            rateQueryWrapper.eq("is_deleted", IsDeletedEnum.N.getCode());
            rateQueryWrapper.eq("rate_type", code);
            rateQueryWrapper.eq("org_id", orgIds.get(i));
            if (StringUtils.isNotBlank(riskForm.getChargePeriodValue())) {
                rateQueryWrapper.le("charge_period_lower_value", riskForm.getChargePeriodValue());
                rateQueryWrapper.ge("charge_period_upper_value", riskForm.getChargePeriodValue());
            }
            if (StringUtils.isNotBlank(riskForm.getCoveragePeriodValue())) {
                rateQueryWrapper.le("coverage_period_lower_value", riskForm.getCoveragePeriodValue());
                rateQueryWrapper.ge("coverage_period_upper_value", riskForm.getCoveragePeriodValue());
            }
            if (riskForm.getApplyDate() != null) {
                rateQueryWrapper.le("start_time", riskForm.getApplyDate());
                rateQueryWrapper.ge("end_time", riskForm.getApplyDate());
            }
            if (StringUtils.isNotBlank(riskForm.getChargeIntervalEnum())) {
                rateQueryWrapper.like("charge_interval_enum", riskForm.getChargeIntervalEnum());
            }
            if (riskForm.getPensionAge() != null) {
                rateQueryWrapper.le("pension_age_lower", riskForm.getPensionAge());
                rateQueryWrapper.ge("pension_age_upper", riskForm.getPensionAge());
            }
            if (riskForm.getPolicyYear() != null) {
                rateQueryWrapper.le("pay_year_lower", riskForm.getPolicyYear());
                rateQueryWrapper.ge("pay_year_upper", riskForm.getPolicyYear());
            }
            if (riskForm.getInsSchemeId() != null) {
                rateQueryWrapper.eq("ins_scheme_id", riskForm.getInsSchemeId());
            }
            if (StringUtils.isNotBlank(riskForm.getFactor1Value())) {
                rateQueryWrapper.eq("factor1_value", riskForm.getFactor1Value());
            }
            if (StringUtils.isNotBlank(riskForm.getFactor2Value())) {
                rateQueryWrapper.eq("factor2_value", riskForm.getFactor2Value());
            }
            if (StringUtils.isNotBlank(riskForm.getFactor3Value())) {
                rateQueryWrapper.eq("factor3_value", riskForm.getFactor3Value());
            }
            List<ImcInsRate> imcInsRates = this.imcInsRateMapper.selectList(rateQueryWrapper);
            if (CollectionUtils.isEmpty(imcInsRates)) {
                continue;
            }
            if (imcInsRates.size() > 1) {
//                throw new BusinessException(RateTypeEnum.getNameByCode(code)+":费率配置发生冲突，请检查");
                throw new BusinessException("请检查是否能确认唯一费率" + RateTypeEnum.getNameByCode(code) + "参数:" + riskForm.toString() );
            }
            returnRate = imcInsRates.get(0);
        }
        return returnRate;
    }


    private List<ImcInsRate> getRate(OrderRiskForm riskForm) {
        QueryWrapper<ImcInsRate> rateQueryWrapper = new QueryWrapper<>();
        rateQueryWrapper.eq("repo_ins_id", riskForm.getRepoInsId());
        rateQueryWrapper.eq("is_deleted", IsDeletedEnum.N.getCode());
        //rateQueryWrapper.eq("tenant_id",SecurityUtils.getTenantId());
        rateQueryWrapper.eq("org_id", riskForm.getSettleOrgId());
        if (StringUtils.isNotBlank(riskForm.getChargePeriodValue())) {
            rateQueryWrapper.le("charge_period_lower_value", riskForm.getChargePeriodValue());
            rateQueryWrapper.ge("charge_period_upper_value", riskForm.getChargePeriodValue());
        }
        if (StringUtils.isNotBlank(riskForm.getCoveragePeriodValue())) {
            rateQueryWrapper.le("coverage_period_lower_value", riskForm.getCoveragePeriodValue());
            rateQueryWrapper.ge("coverage_period_upper_value", riskForm.getCoveragePeriodValue());
        }
        if (riskForm.getApplyDate() != null) {
            rateQueryWrapper.le("start_time", riskForm.getApplyDate());
            rateQueryWrapper.ge("end_time", riskForm.getApplyDate());
        }
        if (StringUtils.isNotBlank(riskForm.getChargeIntervalEnum())) {
            rateQueryWrapper.like("charge_interval_enum", riskForm.getChargeIntervalEnum());
        }
        if (riskForm.getPensionAge() != null) {
            rateQueryWrapper.le("pension_age_lower", riskForm.getPensionAge());
            rateQueryWrapper.ge("pension_age_upper", riskForm.getPensionAge());
        }
        /*int month = DateUtils.getDifMonth(checkDate,DateUtils.getNowDate());
        int payYear = (int)(month+1)/12+1;*/
        if (riskForm.getPolicyYear() != null) {
            rateQueryWrapper.le("pay_year_lower", riskForm.getPolicyYear());
            rateQueryWrapper.ge("pay_year_upper", riskForm.getPolicyYear());
        }
        if (riskForm.getInsSchemeId() != null) {
            rateQueryWrapper.eq("ins_scheme_id", riskForm.getInsSchemeId());
        }
        if (StringUtils.isNotBlank(riskForm.getFactor1Value())) {
            rateQueryWrapper.eq("factor1_value", riskForm.getFactor1Value());
        }
        if (StringUtils.isNotBlank(riskForm.getFactor2Value())) {
            rateQueryWrapper.eq("factor2_value", riskForm.getFactor2Value());
        }
        if (StringUtils.isNotBlank(riskForm.getFactor3Value())) {
            rateQueryWrapper.eq("factor3_value", riskForm.getFactor3Value());
        }
        return this.imcInsRateMapper.selectList(rateQueryWrapper);
    }

    /**
     * 根据条件获取险种产品费率列表
     *
     * @param riskForm 险种产品信息
     * @return 结果
     */
    @Override
    public List<InsRateVo> getRateList(OrderRiskForm riskForm) {
        List<ImcInsRate> rates = this.getRate(riskForm);
        List<InsRateVo> list = new ArrayList<>();
        if (rates.size() > 0) {
            for (ImcInsRate rate : rates) {
                InsRateVo vo = new InsRateVo();
                BeanUtils.copyProperties(rate, vo);
                if (vo.getInsSchemeId() != null) {
                    ImcInsScheme scheme = this.imcInsSchemeMapper.selectById(vo.getInsSchemeId());
                    vo.setInsSchemeValue(scheme.getInsSchemeValue());
                }
                list.add(vo);
            }
        }
        return list;
    }
}
